﻿// <copyright file="CommunityCommentsByUrl.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-4-13</date>
// <summary>CommunityCommentsByUrl Silverlight CLR class definition</summary>

namespace NYTimes
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using NYTimes.Core;
    using NYTimes.Data;

    /// <summary>
    /// The URL Match type
    /// </summary>
    public enum UrlMatchType
    {
        /// <summary>
        /// If you specify exact-match, the first 25 comments associated with that URL will be 
        /// returned if the URL is found. If there is no exact match, an empty result set will be 
        /// returned.
        /// </summary>
        ExactMatch,

        /// <summary>
        /// If you specify closest-stem-match, the most similar URLs will be returned. (No comments 
        /// will be returned.) 
        /// </summary>
        ClosestStemMatch
    }

    /// <summary>
    /// New York Times Community Comments by URL API
    /// </summary>
    /// <remarks>http://developer.nytimes.com/docs/community_api#commentsURL
    /// <list type="table">
    /// <listheader>
    /// <term>Application Resource Key</term>
    /// <description>Key to add to application resources</description>
    /// </listheader>
    /// <item>
    /// <term>
    /// NYTCommunityKey
    /// </term>
    /// <description>Community API Key</description>
    /// </item>
    /// <item>
    /// <term>
    /// NYTCommunityQPS
    /// </term>
    /// <description>Rate Limiting (default 30 QPS)</description>
    /// </item>
    /// </list>
    /// </remarks>
    public class CommunityCommentsByUrl : CommunityBase
    {
        #region Fields
        /// <summary>
        /// the offset
        /// </summary>
        private int offset;

        /// <summary>
        /// the query URL
        /// </summary>
        private Uri url;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the CommunityCommentsByUrl class. 
        /// </summary>
        public CommunityCommentsByUrl()
        {
            this.Assets = new ObservableCollection<Asset>();

            this.MaxResults = 20;

            if (SampleData.IsInDesignTool)
            {
                var xml = SampleData.GetSampleData("CommunityCommentsByDate.xml");

                this.ParseXml(xml);
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the sort
        /// </summary>
        [Description("The sort order for the results.")]
        public CommentSortType Sort { get; set; }

        /// <summary>
        /// Gets the offset for the results
        /// </summary>
        public int Offset
        {
            get
            {
                return this.offset;
            }

            private set
            {
                this.offset = value;

                this.FetchResults(this.offset == 0);
            }
        }

        /// <summary>
        /// Gets or sets the maximum number of results to return (default is 20)
        /// </summary>
        [Description("the maximum results to get (default is 20)")]
        public int MaxResults { get; set; }

        /// <summary>
        /// Gets or sets the Url
        /// </summary>
        [Description("The URL to look for comments about."),
        TypeConverter(typeof(UriTypeConverter))]
        public Uri Url 
        {
            get
            {
                return this.url;
            }

            set
            {
                if (this.url != value)
                {
                    this.url = value;

                    this.Offset = 0;
                }
            }
        }

        /// <summary>
        /// Gets or sets the match type
        /// </summary>
        [Description("Closest stem match or exact matching for the URL")]
        public UrlMatchType MatchType { get; set; }

        /// <summary>
        /// Gets the assets returned
        /// </summary>
        public ObservableCollection<Asset> Assets { get; private set; }

        #endregion

        #region Methods
        /// <summary>
        /// Generates the URI string
        /// </summary>
        /// <returns>the output URI string</returns>
        public override string GenerateUriFragment()
        {
            var builder = new StringBuilder();

            var urlString = Platform.UrlEncode(this.Url.ToString());

            switch (this.MatchType)
            {
                case UrlMatchType.ClosestStemMatch:
                    builder.AppendFormat(CultureInfo.InvariantCulture, "url/closest-stem-match.xml?url={0}&", urlString);
                    break;

                case UrlMatchType.ExactMatch:
                    builder.AppendFormat(CultureInfo.InvariantCulture, "url/exact-match.xml?url={0}&", urlString);
                    break;
            }

            AppendSortType(builder, this.Sort);

            if (this.Offset > 0)
            {
                builder.AppendFormat(CultureInfo.InvariantCulture, "&offset={0}", this.Offset);
            }
            else
            {
                this.Assets.Clear();
            }

            return builder.ToString();
        }

        /// <summary>
        /// Fetch the next set of results
        /// </summary>
        /// <returns>true if the results are done loading, false otherwise.</returns>
        public override bool FetchNextSet()
        {
            switch (this.MatchType)
            {
                case UrlMatchType.ClosestStemMatch:
                    if (this.Assets.Count < this.MaxResults && this.Assets.Count < this.TotalComments)
                    {
                        this.Offset += 25;

                        return false;
                    }

                    break;

                case UrlMatchType.ExactMatch:
                    if (this.Results.Count < this.MaxResults && this.Results.Count < this.TotalComments)
                    {
                        this.Offset += 25;

                        return false;
                    }

                    break;
            }

            return true;
        }

        /// <summary>
        /// Parse the assets
        /// </summary>
        /// <param name="resultSet">the result set</param>
        public override void Parse(XElement resultSet)
        {
            if (resultSet == null)
            {
                throw new ArgumentNullException("resultSet");
            }

            var results = resultSet.Element("results");

            var totalAssetsFound = results.Element("totalAssetsFound");

            if (totalAssetsFound != null)
            {
                this.TotalComments = int.Parse(totalAssetsFound.Value, CultureInfo.InvariantCulture);

                var assets = from asset in results.Descendants("asset")
                             select new Asset()
                             {
                                 CommentsUrl = new Uri("http://" + asset.Element("assetCommentsURL").Value, UriKind.Absolute),
                                 Url = new Uri(asset.Element("assetURL").Value, UriKind.Absolute)
                             };

                foreach (var asset in assets)
                {
                    this.Assets.Add(asset);
                }
            }
        }

        #endregion
    }
}
